#include "DTH11.h"
#include "stm32f4xx_hal.h"
#include "tx_api.h"
#include "dwt.h"

// 修改为实际使用的GPIO端口和引脚
#define DTH11_GPIO_PORT GPIOA
#define DTH11_GPIO_PIN  GPIO_PIN_4

// 微秒级延时，使用DWT
static void delay_us(uint32_t us) {
    uint64_t start = DWT_GetTimeline_us();
    while ((DWT_GetTimeline_us() - start) < us);
}

// 设置为输出
static void GPIO_SetPinOutput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DTH11_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DTH11_GPIO_PORT, &GPIO_InitStruct);
}

// 设置为输入
static void GPIO_SetPinInput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DTH11_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(DTH11_GPIO_PORT, &GPIO_InitStruct);
}

// 输出高低电平
static void GPIO_WritePin(uint8_t value) {
    HAL_GPIO_WritePin(DTH11_GPIO_PORT, DTH11_GPIO_PIN, value ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

// 读取电平
static uint8_t GPIO_ReadPin(void) {
    return HAL_GPIO_ReadPin(DTH11_GPIO_PORT, DTH11_GPIO_PIN);
}

void DTH11_Init(void) {
    GPIO_SetPinOutput();
    GPIO_WritePin(1); // 默认拉高
}

// 读取一个字节
static uint8_t DTH11_ReadByte(void) {
    uint8_t i, data = 0;
    for (i = 0; i < 8; i++) {
        // 等待低电平结束
        while (GPIO_ReadPin() == 0);
        // 延时30us后读取数据位
        delay_us(30);
        if (GPIO_ReadPin())
            data |= (1 << (7 - i));
        // 等待高电平结束
        while (GPIO_ReadPin() == 1);
    }
    return data;
}

int DTH11_Read(DTH11_Data *data) {
    uint8_t buf[5] = {0};
    int retry = 0;

    // 主机拉低18ms
    GPIO_SetPinOutput();
    GPIO_WritePin(0);
    tx_thread_sleep(TX_TIMER_TICKS_PER_SECOND * 18 / 1000); // 18ms
    GPIO_WritePin(1);
    delay_us(30);
    GPIO_SetPinInput();

    // 等待DTH11响应
    retry = 0;
    while (GPIO_ReadPin() && retry < 100) {
        delay_us(1);
        retry++;
    }
    if (retry >= 100) return -1; // 未响应

    // 等待DTH11拉高
    retry = 0;
    while (!GPIO_ReadPin() && retry < 100) {
        delay_us(1);
        retry++;
    }
    if (retry >= 100) return -2;

    // 等待DTH11拉低
    retry = 0;
    while (GPIO_ReadPin() && retry < 100) {
        delay_us(1);
        retry++;
    }
    if (retry >= 100) return -3;

    // 读取5字节数据
    for (int i = 0; i < 5; i++) {
        buf[i] = DTH11_ReadByte();
    }

    // 校验
    if ((uint8_t)(buf[0] + buf[1] + buf[2] + buf[3]) != buf[4]) {
        return -4; // 校验失败
    }

    data->humidity_int = buf[0];
    data->humidity_dec = buf[1];
    data->temperature_int = buf[2];
    data->temperature_dec = buf[3];
    data->checksum = buf[4];

    return 0; // 成功
}
